package com.heisenhub.common.db.controller;

import com.heisenhub.api.logsapi.async.LogsAsyncUtil;
import com.heisenhub.common.db.enums.PermissionSuffixEnum;
import com.heisenhub.common.db.model.IsDel;
import com.heisenhub.common.db.service.ISuperService;
import com.heisenhub.common.oauth.entity.UuaUser;
import com.heisenhub.common.oauth.holder.LoginUserHolder;
import com.heisenhub.logs.common.enums.LogsOperateEnums;
import com.heisenhub.logs.common.inter.LogsOperateInter;
import com.heisenhub.logs.common.utils.LogsUtils;
import com.heisnenhub.common.module.constant.HttpConstant;
import com.heisnenhub.common.module.enmus.BusinessTypeEnums;
import com.heisnenhub.common.module.entity.IBaseEntity;
import com.heisnenhub.common.module.entity.PageQuery;
import com.heisnenhub.common.module.inter.BusinessTypeEnumsInter;
import com.heisnenhub.common.module.utils.Api;
import com.heisnenhub.common.module.utils.GsonUtils;
import com.heisnenhub.common.module.utils.ThrowExceptionUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.Objects;
import java.util.Optional;

/**
 * @author sen
 * @param <T> 实体对象
 * @param <E> update 和 save 对象的dto
 * @param <Q> 分页对象
 * @param <S>  service 对象
 * @description  抽象Controller  实现 增删改查 基本的接口   doPage分页接口有点特殊  需要在mapper。xml 文件实现  doPage 的sql 完成分页
 * @date 2024/1/8 15:49
 */
@Slf4j
public abstract class AbstractController<T extends IsDel & IBaseEntity  , E extends IBaseEntity, Q extends PageQuery,S extends ISuperService > implements LogsOperateInter {

    // 这个可以使用 自定义的servicce 继承IService  可以见ISuperService
  //  protected abstract ISuperService<T,Q> getService();

    /**
     * 通过注入的方式 获取service对象
     */
    @Autowired
    public S service;


    public abstract BusinessTypeEnumsInter getBusinessTypeEnums();


    /**
     *  检查权限
     * @param suffix
     * @return
     */
    public boolean hasPermission(PermissionSuffixEnum suffix) {
        BusinessTypeEnumsInter businessTypeEnumsInter = Optional.ofNullable(getBusinessTypeEnums()).orElse(BusinessTypeEnums.NONE);
        String permission =businessTypeEnumsInter.getPermission();
        if(StringUtils.isBlank(permission)) return true;
        UuaUser uuaUser = LoginUserHolder.loginUser();
        if(Objects.isNull(uuaUser)) return false;
        Collection<GrantedAuthority> authorities = uuaUser.getAuthorities();
        // TypeTwo的权限检查逻辑
        return  authorities.stream().anyMatch(o -> o.getAuthority().equals(permission+ suffix.getSuffix() ));
    }

    /**
     * 获取到T的 class 类型
     * @return
     */
    public Class<T> getTClass() {

        Type type = getClass().getGenericSuperclass();
        if(!(type instanceof ParameterizedType)) {
            throw new IllegalStateException("Type must be a parameterized type");
        }
        ParameterizedType parameterizedType = (ParameterizedType)type;
        // 获取泛型的具体类型  这里是单泛型
        Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
        if(null == actualTypeArguments || actualTypeArguments.length<1) {
            throw new IllegalStateException("Number of type arguments must be 1");
        }
        return (Class<T>) actualTypeArguments[0];
    }

    /**
     *  转换对象
     * @param form
     * @return
     */
    protected T formConvert(E form ) {
        return GsonUtils.toBean(GsonUtils.toJson(form), this.getTClass());
    }


    /**
     * 是否添加日志
     * @return
     */
    @Override
   public boolean isAddLogs(){
        return true ;
    };

    /**
     *
     * @param businessUniqueCode 唯一id
     * @param details  日记详情
     * @param success  是否成功
     * @param logsOperateEnums  日志枚举
     */
    public void  addLogs(String businessUniqueCode, String details, boolean success, LogsOperateEnums logsOperateEnums){
        try {
            BusinessTypeEnumsInter businessTypeEnums = getBusinessTypeEnums();
            if(isAddLogs() && !Objects.isNull(businessTypeEnums)) {
                LogsAsyncUtil.saveOperateLog(LoginUserHolder.loginUser(), logsOperateEnums.getDesc()+getBusinessTypeEnums().getLogTitle(), getBusinessTypeEnums() ,businessUniqueCode ,details ,success , logsOperateEnums);
            }
        }catch (Exception e){
            log.error("【保存日志报错】 {}",e);
        }
    }


    /**
     *  新增一条记录
     *
     * @param addDto 对象
     * @return 新增结果
     */
    @PostMapping(name="添加{}")
    @Transactional
    public Api save(@RequestBody @Validated E addDto) {
        ThrowExceptionUtils.isTure(!hasPermission(PermissionSuffixEnum.ADD)).throwMessage(HttpConstant.HttpMsg.MSG_NO_PREM);
        T entity = formConvert(addDto);
        boolean save = service.save(entity);
        addLogs(String.valueOf(entity.getId() ) ,LogsUtils.fieldAdd(addDto) ,save , LogsOperateEnums.SAVE);
        return   Api.of(save).build();
    }

    /**
     * 分页查询  doPage 分页
     * @deprecated 分页接口有点特殊  需要在mapper。xml 文件实现  doPage 的sql 完成分页
     * @param page 查询条件
     * @return 分页列表
     */
    @PostMapping(path = "/doPage", name="分页查询{}")
   // @Deprecated
    public Api doPage(@RequestBody Q page) {
        ThrowExceptionUtils.isTure(!hasPermission(PermissionSuffixEnum.PAGE)).throwMessage(HttpConstant.HttpMsg.MSG_NO_PREM);
        return Api.ok(service.doPage(page));

    }




    
    /**
     * 根据主键获取实体对象
     *
     * @param id 主键
     * @return 告警通知
     */
    @GetMapping(path = "/{id}",name="获取{}")
    public Api get(@PathVariable("id") Long id) {
        ThrowExceptionUtils
                .orThrow(!hasPermission(PermissionSuffixEnum.VIEW) , HttpConstant.HttpMsg.MSG_NO_PREM)
                .or(id == null , HttpConstant.HttpMsg.MSG_ID_IS_NULL);
        T entity = (T) service.findById(id);
        return Api.ok(entity);
    }

    /**
     * 修改对象
     * @param updateDto 修改对象
     * @return 修改结果
     */
    @PutMapping(path = "/{id}", name="修改{}")
    @Transactional
    public Api update(@PathVariable Long id, @Validated @RequestBody E updateDto) {
        ThrowExceptionUtils
                .orThrow(!hasPermission(PermissionSuffixEnum.UPDATE) , HttpConstant.HttpMsg.MSG_NO_PREM)
                .or(id == null , HttpConstant.HttpMsg.MSG_ID_IS_NULL)
                .or(updateDto.getId()== null ,"对象id为空" )
                .or(!id.equals(updateDto.getId()) ,"id异常" );
        T originalObj = (T)  service.findByIdThrow(id);
        T entity = formConvert(updateDto);
        boolean update = service.updateById(entity);
        addLogs(String.valueOf(entity.getId() ) ,LogsUtils.fieldChange(originalObj,updateDto) ,update , LogsOperateEnums.UPTATE);
        return   Api.of(update)
                .build();
    }

    /**
     * 根据主键删除数据
     * @param id 主键
     * @return 删除结果
     */
    @DeleteMapping(path = "/{id}", name="删除{}")
    public Api delete(@PathVariable Long id) {

        ThrowExceptionUtils
                .orThrow(!hasPermission(PermissionSuffixEnum.DELETE) , HttpConstant.HttpMsg.MSG_NO_PREM)
                .or(id == null , HttpConstant.HttpMsg.MSG_ID_IS_NULL);
        return   Api.of(service.delById(id))
                .build();
    }





}
